package com.glsc.ngateway.oaflow.service;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.glsc.ngateway.common.api.common.enums.GatewayConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowSubscribeOaFlowInfo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowSubscribeOaFlowInfoRepository;
import com.glsc.ngateway.common.base.utils.redis.IbltRedis;
import com.glsc.ngateway.common.base.utils.redis.RedisKey;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowMetaTable;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowSyncLog;
import com.glsc.ngateway.common.base.domain.oracle.ecology.WorkflowRequestbase;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrEmpDto;
import com.glsc.ngateway.common.api.oaflow.dto.other.FlowFieldDetail;
import com.glsc.ngateway.common.api.oaflow.dto.other.FlowFieldMain;
import com.glsc.ngateway.common.api.oaflow.dto.other.FlowFieldProperties;
import com.glsc.ngateway.common.api.oaflow.dto.other.FlowObject;
import com.glsc.ngateway.common.api.ldap.resp.AppEhrResponse;
import com.glsc.ngateway.common.base.enums.OaFlowSyncLogStatusEnum;
import com.glsc.ngateway.common.base.enums.OaWorkFlowRequestTableStatusEnum;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowSyncLogRepository;
import com.glsc.ngateway.common.base.repo.oracle.ecology.HrmresourceRepository;
import com.glsc.ngateway.common.base.repo.oracle.ecology.WorkflowRequestbaseRepository;
import com.glsc.ngateway.common.api.common.utils.JsonUtil;
import com.glsc.ngateway.oaflow.exception.OaflowException;
import com.glsc.ngateway.common.api.ldap.feign.IFeignLdapService;
import com.glsc.ngateway.oaflow.utils.FanweiSupport;
import com.glsc.ngateway.oaflow.wsclients.wsdl.end.ForceOver;
import com.glsc.ngateway.oaflow.wsclients.wsdl.end.ForceOverResponse;
import com.glsc.ngateway.oaflow.wsclients.wsdl.end.WsClientEndFlow;
import com.glsc.ngateway.oaflow.wsclients.wsdl.workflow.CreateOAWorkflowOfJson;
import com.glsc.ngateway.oaflow.wsclients.wsdl.workflow.CreateOAWorkflowOfJsonResponse;
import com.glsc.ngateway.oaflow.wsclients.wsdl.workflow.WsClient;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.ws.client.WebServiceClientException;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.lang.reflect.Field;
import java.util.*;

@Component
public class AddFlowService {

    Logger logger = LoggerFactory.getLogger(AddFlowService.class);

    @Resource
    private IFeignLdapService iFeignLdapService;
    @Autowired
    HrmresourceRepository hrmresourceRepository;
    @Autowired
    FlowService flowService;
    @Autowired
    private TOaFlowSyncLogRepository syncLogRepo;
    @Autowired
    private WorkflowRequestbaseRepository oaFlowRepo;
    @Autowired
    WsClient wsClient;
    @Autowired
    WsClientEndFlow wsClientEndFlow;
    @Resource
    IbltRedis ibltRedis;
    @Value("${fixedincome.accountDeptId}")
    public String accountDeptId;
    @Resource
    public TOaFlowSubscribeOaFlowInfoRepository subOaFlowInfoRepo;
    @Resource
    private WorkflowRequestbaseRepository workflowRequestbaseRepo;

    public Map<String, String> endOaFlow(String requestid) {
        Map<String, String> parm = new HashMap<>();
        parm.put("requestid", requestid);
        Map<String, String> dataMap = new HashMap<String, String>();
        ForceOver req = new ForceOver();
        req.setIn0(JSONObject.toJSON(parm).toString());
        logger.info("endOaFlow接口请求:" + req);
//        ForceOverResponse res = (ForceOverResponse) wsClientEndFlow.callWebService(req);
        ForceOverResponse res = new ForceOverResponse();
        try {
            // 尝试使用主配置发送请求
            res = (ForceOverResponse) wsClientEndFlow.callWebService(req);
        } catch (WebServiceClientException e) {
            // 捕获WebServiceClientException异常，这通常表示网络问题或Web服务不可用
            // 在这里可以记录日志或执行其他错误处理逻辑
            // 然后尝试使用备用配置发送请求
            logger.error("oaCallEndException"+e);
            res = (ForceOverResponse) wsClientEndFlow.callWebServiceBack(req);
        }
        String result = res.getOut();
        logger.info("endOaFlow接口返回:" + result);
        if (JsonUtil.isJson(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            dataMap = JSONObject.parseObject(jsonObject.toJSONString(), new TypeReference<Map<String, String>>() {
            });
        } else {
            dataMap = FanweiSupport.mapChange(result);
        }

        logger.info("endOaFlow接口返回DataMap:" + dataMap);
        if (dataMap.isEmpty()) {
            return GatewayConstant.FANWEI_DEFAULT_MAP;
        } else {
            return dataMap;
        }
    }

    public Map<String, String> addOaFlow(String params) {
        return addOaFlow(params, false);
    }

    public Map<String, String> addOaFlow(String params, boolean subscribe) {
        Integer requestId = 0;
        Map<String, String> dataMap = new HashMap<String, String>();

//        CommonWorkflowService cwService = new CommonWorkflowService();
//        CommonWorkflowServicePortType cportType = cwService.getCommonWorkflowServiceHttpPort();
//        String result= cportType.createOAWorkflowOfJson(params);
        CreateOAWorkflowOfJson req = new CreateOAWorkflowOfJson();
        req.setIn0(params);
        logger.info("req{}", req);
//        CreateOAWorkflowOfJsonResponse res = (CreateOAWorkflowOfJsonResponse) wsClient.callWebService(req);
        CreateOAWorkflowOfJsonResponse res = new CreateOAWorkflowOfJsonResponse();
        try {
            // 尝试使用主配置发送请求
            res = (CreateOAWorkflowOfJsonResponse) wsClient.callWebService(req);
        } catch (WebServiceClientException e) {
            // 捕获WebServiceClientException异常，这通常表示网络问题或Web服务不可用
            // 在这里可以记录日志或执行其他错误处理逻辑
            // 然后尝试使用备用配置发送请求
            logger.error("oacreateException"+e);
            res = (CreateOAWorkflowOfJsonResponse) wsClient.callWebServiceBack(req);
        }
        String result = res.getOut();
        logger.info("addOaFlow接口返回:" + result);
        if (JsonUtil.isJson(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            dataMap = JSONObject.parseObject(jsonObject.toJSONString(), new TypeReference<Map<String, String>>() {
            });
        } else {
            dataMap = FanweiSupport.mapChange(result);
        }

        logger.info("dataMap:" + dataMap);
        //如果选择订阅，则加入到记录表中，
        if (!subscribe) {
            logger.info("创建oa流程：{}无需订阅", requestId);
        } else if (!dataMap.containsKey("requestid")) {
            logger.error("创建oa流程记录：未发现requestid");
        } else {
            Map<String, String> finalDataMap = dataMap;
            new Thread(() -> {
                Integer requestid = Integer.valueOf(finalDataMap.get("requestid"));
                WorkflowRequestbase reqtBase = workflowRequestbaseRepo.findByRequestid(requestid).orElseThrow(() -> new OaflowException("未找到oa流程信息：" + requestid));
                subOaFlowInfoRepo.save(TOaFlowSubscribeOaFlowInfo.builder()
                        .requestId(requestid)
                        .lastUpdateTime(reqtBase.getLastoperatedate().atTime(reqtBase.getLastoperatetime()))
                        .currentNodeType(reqtBase.getCurrentnodetype())
                        .status(reqtBase.getStatus())
                        .build());
            }).start();
        }

        if (dataMap.isEmpty()) {
            return GatewayConstant.FANWEI_DEFAULT_MAP;
        } else {
            return dataMap;
        }
    }

    public FlowObject operateOAMessage(Map<String, Object> dataMap, List<TOaFlowMetaTable> flowMetaDataList, String workFlowId) throws Exception {

        FlowObject fo = new FlowObject("sysadmin", "workcode", workFlowId, "", "");
        //申请人
        String sqr = dataMap.get("applicant").toString();
        AppEhrResponse<LdapEhrEmpDto> resp = iFeignLdapService.getLdapEhrEmp(sqr, null, false);
        if (Objects.isNull(resp) || !resp.isSuccess() || Objects.isNull(resp.getData())) {
            throw new Exception("未找到人员信息, " + sqr);
        }
        LdapEhrEmpDto appInfo = resp.getData();
        String appDepartId = "";
        String appCompId = "";
        if (!StringUtils.isEmpty(appInfo.getOaDeptId())) {
            appDepartId = appInfo.getOaDeptId().toString();
        }
        if (!StringUtils.isEmpty(appInfo.getOaCompId())) {
            appCompId = appInfo.getOaCompId().toString();
        }

        logger.info("查询部门ID:" + appDepartId + "，查询公司ID:" + appCompId);

        dataMap.put("applicantDepart", appDepartId);
        dataMap.put("applicantComp", appCompId);
        List<FlowFieldDetail> flowDetailList = new ArrayList<FlowFieldDetail>();
        List<FlowFieldMain> flowMainList = new ArrayList<FlowFieldMain>();
        List<TOaFlowMetaTable> flowMetaTempList = new ArrayList<TOaFlowMetaTable>();
        for (TOaFlowMetaTable flowMetaData : flowMetaDataList) {
//            System.out.println("come to the param: "+flowMetaData.getFlowFieldName()+"========================");
            switch (flowMetaData.getFieldType()) {
                case GatewayConstant.HEADER_LEVEL:
                    getHeaderContent(fo, flowMetaData, dataMap);
                    break;
                case GatewayConstant.MAIN_LEVEL:
                    getMainFlowContent(flowMainList, flowMetaData, dataMap);
                    break;
                default:
                    flowMetaTempList.add(flowMetaData);
                    break;
            }
        }
        getDetailFlowContent(flowDetailList, flowMetaTempList, dataMap);
        fo.setMainMap(flowMainList);
        fo.setDetailList(flowDetailList);

        return fo;
    }

    public FlowObject operateOAMessageWithDeptId(Map<String, Object> dataMap, List<TOaFlowMetaTable> flowMetaDataList, String workFlowId) throws Exception {

        FlowObject fo = new FlowObject("sysadmin", "workcode", workFlowId, "", "");
        //申请人
        String sqr = dataMap.get("applicant").toString();
        AppEhrResponse<LdapEhrEmpDto> resp = iFeignLdapService.getLdapEhrEmp(sqr, null, false);
        if (Objects.isNull(resp) || !resp.isSuccess() || Objects.isNull(resp.getData())) {
            throw new Exception("未找到人员信息, " + sqr);
        }
        LdapEhrEmpDto appInfo = resp.getData();
        String appDepartId = "";
        String appCompId = "";
        if (!StringUtils.isEmpty(appInfo.getOaDeptId())) {
            appDepartId = appInfo.getOaDeptId().toString();
        }
        if (!StringUtils.isEmpty(appInfo.getOaCompId())) {
            appCompId = appInfo.getOaCompId().toString();
        }

        logger.info("查询部门ID:" + appDepartId + "，查询公司ID:" + appCompId);

        if (Objects.isNull(dataMap.get("applicantDepart"))) {
            dataMap.put("applicantDepart", appDepartId);
        }
        if (Objects.isNull(dataMap.get("applicantComp"))) {
            dataMap.put("applicantComp", appCompId);
        }
        List<FlowFieldDetail> flowDetailList = new ArrayList<FlowFieldDetail>();
        List<FlowFieldMain> flowMainList = new ArrayList<FlowFieldMain>();
        List<TOaFlowMetaTable> flowMetaTempList = new ArrayList<TOaFlowMetaTable>();
        for (TOaFlowMetaTable flowMetaData : flowMetaDataList) {
//            System.out.println("come to the param: "+flowMetaData.getFlowFieldName()+"========================");
            switch (flowMetaData.getFieldType()) {
                case GatewayConstant.HEADER_LEVEL:
                    getHeaderContent(fo, flowMetaData, dataMap);
                    break;
                case GatewayConstant.MAIN_LEVEL:
                    getMainFlowContent(flowMainList, flowMetaData, dataMap);
                    break;
                default:
                    flowMetaTempList.add(flowMetaData);
                    break;
            }
        }
        getDetailFlowContent(flowDetailList, flowMetaTempList, dataMap);
        fo.setMainMap(flowMainList);
        fo.setDetailList(flowDetailList);

        return fo;
    }


    public void getHeaderContent(FlowObject fo, TOaFlowMetaTable flowMetaData, Map<String, Object> dataMap) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        Field[] headerFields = Class.forName("com.glsc.ngateway.common.api.oaflow.dto.other.FlowObject").getDeclaredFields();
        if (dataMap.containsKey(flowMetaData.getInterfaceFieldName())) {
            for (int i = 0; i < headerFields.length; i++) {
                headerFields[i].setAccessible(true); // 取消属性的访问权限控制，即使private属性也可以进行访问。
                if (headerFields[i].getName().equals(flowMetaData.getFlowFieldName())) {
                    headerFields[i].set(fo, dataMap.getOrDefault(flowMetaData.getInterfaceFieldName(), flowMetaData.getDefaultValue()));
                }
            }
        }
    }


    /**
     * @param flowMainList
     * @param flowMetaData
     * @param dataMap
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @Descritpion 整理流程元素信息
     */
    public void getMainFlowContent(List<FlowFieldMain> flowMainList, TOaFlowMetaTable flowMetaData, Map<String, Object> dataMap) {

        if (dataMap.containsKey(flowMetaData.getInterfaceFieldName())) {
//            System.out.println("this field: "+flowMetaData.getFlowFieldName()+" --- is doc? "+flowMetaData.getIsDoc()+" --- is person? "+flowMetaData.getIsPerson());
            if (flowMetaData.getIsPerson().equals(GatewayConstant.IS_PERSON)) {
                conformPersonInfo(flowMainList, flowMetaData, dataMap);
            } else {
                if (flowMetaData.getIsDoc().equals(GatewayConstant.IS_DOC)) {
                    Map<String, String> docMap = (Map<String, String>) dataMap.getOrDefault(flowMetaData.getInterfaceFieldName(), flowMetaData.getDefaultValue());
                    flowMainList.add(new FlowFieldMain(new FlowFieldProperties(flowMetaData.getFlowFieldName(), docMap.get("annexId"), "", flowMetaData.getIsDoc(), docMap.get("annexName"))));
                } else {
                    flowMainList.add(new FlowFieldMain(new FlowFieldProperties(flowMetaData.getFlowFieldName(), dataMap.getOrDefault(flowMetaData.getInterfaceFieldName(), flowMetaData.getDefaultValue()).toString(), "", flowMetaData.getIsDoc(), "")));
                }
            }
        } else if (Strings.isNotBlank(flowMetaData.getDefaultValue())) {
            flowMainList.add(new FlowFieldMain(new FlowFieldProperties(flowMetaData.getFlowFieldName(), flowMetaData.getDefaultValue(), "", flowMetaData.getIsDoc(), "")));
        }
    }


    public void getDetailFlowContent(List<FlowFieldDetail> flowDetailsList, List<TOaFlowMetaTable> flowMetaDataList, Map<String, Object> dataMap) throws Exception {


        if (dataMap.containsKey("detailList")) {
            List<Map<String, Object>> detailList = (List<Map<String, Object>>) dataMap.get("detailList");
            for (Map<String, Object> detailMap : detailList) {
                Integer detailIndex = Integer.valueOf(detailMap.get("detailIndex").toString());
                List<FlowFieldMain> ffmList = new ArrayList<FlowFieldMain>();
                for (TOaFlowMetaTable fmd : flowMetaDataList) {
                    if (fmd.getDetailIndex().equals(detailMap.get("detailIndex").toString())) {
                        feildTransform(detailMap, fmd, ffmList);
                    }
                }
                FlowFieldDetail flowFieldDetail = new FlowFieldDetail(detailIndex + "", ffmList);
                flowDetailsList.add(flowFieldDetail);
            }
        }
    }


    public void feildTransform(Map<String, Object> detailMap, TOaFlowMetaTable fmd, List<FlowFieldMain> ffmList) throws Exception {

        if (detailMap.containsKey(fmd.getInterfaceFieldName())) {
            if (fmd.getIsDoc().equals(GatewayConstant.IS_DOC)) {
                Map<String, String> docMap = (Map<String, String>) detailMap.getOrDefault(fmd.getInterfaceFieldName(), fmd.getDefaultValue());
                ffmList.add(new FlowFieldMain(new FlowFieldProperties(fmd.getFlowFieldName(), docMap.get("annexId").toString(), "", fmd.getIsDoc(), docMap.get("annexName").toString())));
            } else if (fmd.getInterfaceFieldName().endsWith("Department") && fmd.getIsPerson().equals(GatewayConstant.IS_PERSON)) {
                //无锡分公司总经理室 转成 208
                ffmList.add(new FlowFieldMain(new FlowFieldProperties(fmd.getFlowFieldName(), flowService.getDepartmentId(detailMap.getOrDefault(fmd.getInterfaceFieldName(), fmd.getDefaultValue()).toString()), "", fmd.getIsDoc(), "")));
            } else if (fmd.getIsPerson().equals(GatewayConstant.IS_PERSON)) {
                //lm 转成 3514
                ffmList.add(new FlowFieldMain(new FlowFieldProperties(fmd.getFlowFieldName(), flowService.getUserId(detailMap.getOrDefault(fmd.getInterfaceFieldName(), fmd.getDefaultValue()).toString()), "", fmd.getIsDoc(), "")));
            } else {
                ffmList.add(new FlowFieldMain(new FlowFieldProperties(fmd.getFlowFieldName(), Optional.ofNullable(detailMap.get(fmd.getInterfaceFieldName())).map(Object::toString).orElse(fmd.getDefaultValue()), "", fmd.getIsDoc(), "")));
            }
        } else if (Strings.isNotBlank(fmd.getDefaultValue())) {
            ffmList.add(new FlowFieldMain(new FlowFieldProperties(fmd.getFlowFieldName(), fmd.getDefaultValue(), "", fmd.getIsDoc(), "")));
        }
    }

    /**
     * @param flowMainList
     * @param flowMetaData
     * @param dataMap
     * @Description 整理人员，部门，公司信息
     */
    public void conformPersonInfo(List<FlowFieldMain> flowMainList, TOaFlowMetaTable flowMetaData, Map<String, Object> dataMap) {

        //适配多个人员,sql添加引号
        String persons = dataMap.getOrDefault(flowMetaData.getInterfaceFieldName(), flowMetaData.getDefaultValue()).toString();
        StringBuffer sb = new StringBuffer();
        if (persons != null && persons.contains(",")) {
            String[] per = persons.split(",");
            for (int i = 0; i < per.length; i++) {
                if (i == per.length - 1) {
                    sb.append("'" + per[i] + "'");
                } else {
                    sb.append("'" + per[i] + "'").append(",");
                }
            }
        } else {
            sb.append("'" + persons + "'");
        }
        FlowFieldProperties ffpp = new FlowFieldProperties(flowMetaData.getFlowFieldName(), sb.toString(), GatewayConstant.PERSON_SQL, "0", "");
        //FlowFieldProperties ffpa = new FlowFieldProperties(GatewayConstant.APPLICANT_APART_NAME,GatewayConstant.APPLICANT_APART_VALUE,"","0","");
        //FlowFieldProperties ffpm = new FlowFieldProperties(GatewayConstant.APPLICANT_COM_NAME,GatewayConstant.APPLICANT_COM_VALUE,"","0","");
        flowMainList.add(new FlowFieldMain(ffpp));
        //flowMainList.add(new FlowFieldMain(ffpa));
        //flowMainList.add(new FlowFieldMain(ffpm));
    }

    public FlowObject operateOAMessage(String workflowId, Map<String, Object> dataMap, List<TOaFlowMetaTable> metaList) throws Exception {
        FlowObject fo = new FlowObject("sysadmin", "workcode", workflowId, "", "");
        List<FlowFieldDetail> flowDetailList = new ArrayList<FlowFieldDetail>();
        List<FlowFieldMain> flowMainList = new ArrayList<FlowFieldMain>();
        List<TOaFlowMetaTable> flowMetaTempList = new ArrayList<TOaFlowMetaTable>();
        for (TOaFlowMetaTable flowMetaData : metaList) {
            switch (flowMetaData.getFieldType()) {
                case GatewayConstant.HEADER_LEVEL:
                    getHeaderContent(fo, flowMetaData, dataMap);
                    break;
                case GatewayConstant.MAIN_LEVEL:
                    getMainFlowContent(flowMainList, flowMetaData, dataMap);
                    break;
                default:
                    flowMetaTempList.add(flowMetaData);
                    break;
            }
        }
        getDetailFlowContent(flowDetailList, flowMetaTempList, dataMap);
        fo.setMainMap(flowMainList);
        fo.setDetailList(flowDetailList);

        return fo;
    }

    public Map<String, String> endOaFlow(@NotBlank String workflowId, @NotBlank String taskId) {
        String key = RedisKey.getOaflowSyncKey(workflowId, taskId);
        Map<String, String> res = Collections.EMPTY_MAP;
        //先抢锁，在取消

        if (!ibltRedis.lock(key)) {
            logger.info("endOaFlow error：redis抢锁失败， key-" + key);
            return res;
        }
        try {
            TOaFlowSyncLog log = syncLogRepo.findByWorkflowIdAndTaskId(workflowId, taskId);
            if (Objects.isNull(log)) {
                logger.info("结束流程同步oa：流程尚未同步");
            } else if (OaFlowSyncLogStatusEnum.UNSYNC.getCode().equals(log.getStatus())) {
                //未同步，在查一遍oa
                Optional<WorkflowRequestbase> oaFlow = oaFlowRepo.findByRequestid(log.getRequestId());
                //若oa侧已有流程
                if (oaFlow.isPresent()) {
                    //若oa侧还未结束，则将其结束
                    if (!OaWorkFlowRequestTableStatusEnum.isEnd(oaFlow.get().getStatus())) {
                        res = endOaFlow(String.valueOf(log.getRequestId()));
                    }
                    log.setStatus(OaFlowSyncLogStatusEnum.END_GATEWAY.getCode());
                } else {
                    //否则标记取消
                    log.setStatus(OaFlowSyncLogStatusEnum.CANCELLED.getCode());
                }
                syncLogRepo.save(log);
            } else if (OaFlowSyncLogStatusEnum.SYNCED.getCode().equals(log.getStatus())) {
                res = endOaFlow(String.valueOf(log.getRequestId()));
                //已同步了，就直接结束
                log.setStatus(OaFlowSyncLogStatusEnum.END_GATEWAY.getCode());
                syncLogRepo.save(log);
            }
        } finally {
            ibltRedis.unlock(key);
        }
        return res;
    }
}
